#include <memory.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include "pal/lane_cmd_parse.h"
#include "pal/lane_cmd_parse_fn.h"
#include "pal/lane_control.h"
#include "CxlUtil.h"
#include "userLog.h"
#include "semUntil.h"
#include <sys/wait.h>
#include "common/pidfile.h"
#include "hal/imx6/src/hal_gps_uv.h"
#include "pending_data_queue.h"
#include "sqlLoop.h"
#include "voiceChedaoji.h"

#define ERROR_FRAME_LEN 1

// 服务器心跳时间间隔
#define LANE_HEART_BEAT_TIME 20 * 1000

#ifndef FIRM_WARE_DIR
#define FIRM_WARE_DIR "/tmp/updateFirmware"
#endif

#ifndef FIRM_WARE_FAIL
#define FIRM_WARE_FAIL 1
#endif

#ifndef FIRM_WARE_RECVING
#define FIRM_WARE_RECVING 2
#endif

#ifndef FIRM_WARE_DONE
#define FIRM_WARE_DONE 3
#endif

#define PATH_NAME_FORMAT "%s/%d_%d"

#define RE_REGISTER_TIME_OUT 10 * 1000

#define SERV_HB_LOG_MAX_NUM 100
static uint8_t serv_hb_log_num = 0;

static uint16_t firm_ware_block_all_num = 0;

static uv_idle_t idler;

static uint8_t parse_block(uint8_t *buf, uint16_t packet_size, uint16_t *file_code);
static void start_idle_response_task(uint16_t block_no);
static void send_firm_ware_response(uv_idle_t *handle);
static void send_firm_ware_response_last_one(bool isSuccess, uint16_t fileCode);
static void setReserveFrame(uint8_t *buf, ssize_t len);

static ReserveFrameT reserveFrame;

void initReserveFrame()
{
    memset(&reserveFrame, 0, sizeof(ReserveFrameT));
    reserveFrame.isReserve = false;
}

ReserveFrameT *getReserveFrame()
{
    return &reserveFrame;
}

uint16_t howManyFrame(const uv_buf_t *buf, ssize_t len)
{
    uint16_t framesNum = 0;
    head_t *nowHead = (head_t *)buf->base;
    ssize_t recvLen = len;
    while (recvLen > 0)
    {
        // 检查合法性
        if (ntohs(nowHead->head) == 0x555a)
        {
            if (recvLen < sizeof(head_t))
            {
                setReserveFrame((uint8_t *)nowHead, recvLen);
                return framesNum;
            }

            uint16_t frameLen = getFrameLen((head_t *)nowHead);
            if (frameLen == 0)
            {
                return framesNum;
            }
            if (frameLen > recvLen)
            {
                setReserveFrame((uint8_t *)nowHead, recvLen);
                return framesNum;
            }
            else
            {
                framesNum++;
                nowHead = headForwardPoint(nowHead, frameLen);
                recvLen -= frameLen;
            }
        }
        else
        {
            return framesNum;
        }
    }
    return framesNum;
}

head_t *headForwardPoint(head_t *head, uint16_t forwardLen)
{
    uint8_t *tmpPoint = (uint8_t *)head;
    tmpPoint += forwardLen;
    return (head_t *)tmpPoint;
}

uint16_t getFrameLen(head_t *head)
{
    switch (head->cmd)
    {
    case REGISTER_CMD:
    {
        return sizeof(respon_registration_t);
    }
    case HEART_BEAT_CMD:
    {
        return sizeof(respon_heart_beat_t);
    }
    case FIRMWARE_CMD:
    {
        return sizeof(file_block_frame_t);
    }
    case PIC_UPLOAD_CMD:
    {
        return sizeof(respon_pic_block_recv_t);
    }
    case CALIBRATION_CMD:
    {
        return sizeof(respon_calibration_t);
    }
    case CALIBRATION_CMD_V2:
    {
        return sizeof(respon_calibration_v2_t);
    }
    default:
        // TODO:这里可能有bug
        return ERROR_FRAME_LEN;
    }
}

bool checkLen(head_t *head, uint16_t frame_len)
{
    uint16_t head_len = ntohs(head->len);
    switch (head->cmd)
    {
    case REGISTER_CMD:
    {
        respon_registration_t *reg_result = (respon_registration_t *)head;

        if (head_len != CAL_FRAME_DATA_LEN(respon_registration_t))
        {
            LOG_ERROR("服务器注册响应数据体长度不正确，服务器响应数据体长度：%d；期望数据体长度：%ld", head_len, CAL_FRAME_DATA_LEN(respon_registration_t));
            hzlog_error(userLog, reg_result, frame_len);
            return false;
        }
        return true;
    }
    case HEART_BEAT_CMD:
    {
        respon_heart_beat_t *heart_beat_result = (respon_heart_beat_t *)head;
        if (head_len != CAL_FRAME_DATA_LEN(respon_heart_beat_t))
        {
            LOG_ERROR("服务器心跳响应数据体长度不正确，服务器响应数据体长度：%d；期望数据体长度：%ld", head_len, CAL_FRAME_DATA_LEN(respon_heart_beat_t));
            hzlog_error(userLog, heart_beat_result, frame_len);
            return false;
        }
        return true;
    }
    case FIRMWARE_CMD:
    {
        file_block_frame_t *pack = (file_block_frame_t *)head;
        if (head_len != CAL_FRAME_DATA_LEN(file_block_frame_t))
        {
            LOG_ERROR("服务器固件下发包数据体长度不正确，服务器响应数据体长度：%d；期望数据体长度：%ld", head_len, CAL_FRAME_DATA_LEN(file_block_frame_t));
            hzlog_error(userLog, pack, frame_len);
            return false;
        }
        return true;
    }
    case PIC_UPLOAD_CMD:
    {
        respon_pic_block_recv_t *pack = (respon_pic_block_recv_t *)head;
        if (head_len != CAL_FRAME_DATA_LEN(respon_pic_block_recv_t))
        {
            LOG_ERROR("服务器图片上传响应数据体长度不正确，服务器响应数据体长度：%d；期望数据体长度：%ld", head_len, CAL_FRAME_DATA_LEN(respon_pic_block_recv_t));
            hzlog_error(userLog, pack, frame_len);
            return false;
        }
        return true;
    }
    case CALIBRATION_CMD:
    {
        respon_calibration_t *pack = (respon_calibration_t *)head;
        if (head_len != CAL_FRAME_DATA_LEN(respon_calibration_t))
        {
            LOG_ERROR("服务器下发标定数据体长度不正确，服务器响应数据体长度：%d；期望数据体长度：%ld", head_len, CAL_FRAME_DATA_LEN(respon_calibration_t));
            hzlog_error(userLog, pack, frame_len);
            return false;
        }
        return true;
    }
    case CALIBRATION_CMD_V2:
    {
        respon_calibration_v2_t *pack = (respon_calibration_v2_t *)head;
        if (head_len != CAL_FRAME_DATA_LEN(respon_calibration_v2_t))
        {
            LOG_ERROR("服务器下发标定v2数据体长度不正确，服务器响应数据体长度：%d；期望数据体长度：%ld", head_len, CAL_FRAME_DATA_LEN(respon_calibration_v2_t));
            hzlog_error(userLog, pack, frame_len);
            return false;
        }
        return true;
    }
    default:
        return false;
    }
}

bool checkCrc(head_t *head, uint16_t frame_len)
{
    uint16_t head_len = ntohs(head->len);
    switch (head->cmd)
    {
    case REGISTER_CMD:
    {
        respon_registration_t *reg_result = (respon_registration_t *)head;

        uint16_t crcResult = LANE_RESPON_CRC_CAL(head, respon_registration_t);
        if (crcResult != ntohs(reg_result->crc))
        {
            LOG_ERROR("注册响应crc校验失败");
            return false;
        }
        return true;
    }
    case HEART_BEAT_CMD:
    {
        respon_heart_beat_t *heart_beat_result = (respon_heart_beat_t *)head;
        uint16_t crcResult = LANE_RESPON_CRC_CAL(head, respon_heart_beat_t);
        if (crcResult != ntohs(heart_beat_result->crc))
        {
            LOG_ERROR("心跳响应crc校验失败");
            return false;
        }
        return true;
    }
    case FIRMWARE_CMD:
    {
        file_block_frame_t *pack = (file_block_frame_t *)head;
        uint16_t crcResult = LANE_RESPON_CRC_CAL(head, file_block_frame_t);
        if (crcResult != ntohs(pack->crc))
        {
            LOG_ERROR("固件分块crc校验失败");
            return false;
        }
        return true;
    }
    case PIC_UPLOAD_CMD:
    {
        respon_pic_block_recv_t *pack = (respon_pic_block_recv_t *)head;
        uint16_t crcResult = LANE_RESPON_CRC_CAL(head, respon_pic_block_recv_t);
        if (crcResult != ntohs(pack->crc))
        {
            LOG_ERROR("图片响应crc校验失败");
            return false;
        }
        return true;
    }
    case CALIBRATION_CMD:
    {
        respon_calibration_t *pack = (respon_calibration_t *)head;
        uint16_t crcResult = LANE_RESPON_CRC_CAL(head, respon_calibration_t);
        if (crcResult != ntohs(pack->crc))
        {
            LOG_ERROR("服务器下发标定crc校验失败");
            return false;
        }
        return true;
    }
    case CALIBRATION_CMD_V2:
    {
        respon_calibration_v2_t *pack = (respon_calibration_v2_t *)head;
        uint16_t crcResult = LANE_RESPON_CRC_CAL(head, respon_calibration_v2_t);
        if (crcResult != ntohs(pack->crc))
        {
            LOG_ERROR("服务器下发标定v2 crc校验失败");
            return false;
        }
        return true;
    }
    default:
        return false;
    }
}

void handleRegisterCmd(respon_registration_t *reg)
{
    if (reg->respon_registration_auth_status == 0x00)
    {
        LOG_INFO("服务器注册成功，开始注册心跳，注册响应报文打印：");
        // 发送心跳定时任务
        uv_connect_t *client = getLaneClientConnect();
        // 注册打印
        hzlog_info(userLog, reg, sizeof(respon_registration_t));
        //设置设备时间
        AppTime sys_time;
        memset(&sys_time, 0, sizeof(sys_time));
        get_time_value(reg->respon_registration_timeBcd, &sys_time);
        chedaoji_set_time(&sys_time);

        laneInterval(laneHeardBeatTask, client->handle, LANE_HEART_BEAT_TIME);
    }
    else
    {
        // 否则重新注册
        LOG_INFO("服务器注册失败，重新注册");
        laneReRegisterSetTimeout(laneRegister, RE_REGISTER_TIME_OUT);
    }
}

void handleHeartBeatCmd(respon_heart_beat_t *heart_beat_result)
{
    // 心跳响应包打印
    serv_hb_log_num++;
    if (serv_hb_log_num > SERV_HB_LOG_MAX_NUM)
    {
        serv_hb_log_num = 0;
        LOG_INFO("收到服务器心跳响应");
    }
    // setHbCountZero();
    // 服务器心跳时间bcd打印
    // hzlog_debug(userLog, heart_beat_result->respon_heart_beat_timeBcd, MEM_SIZE(respon_heart_beat_t, respon_heart_beat_timeBcd));
    //设置设备时间
    AppTime sys_time;
    memset(&sys_time, 0, sizeof(sys_time));
    get_time_value(heart_beat_result->respon_heart_beat_timeBcd, &sys_time);
    chedaoji_set_time(&sys_time);
}

static void updateUploadColToSqlite(uint8_t picName[PIC_FILENAME_MAX_LEN])
{
    SqlAsyncCmd cmd = {0};

    cmd.cmdType = SQL_CMD_TYPE_UPDATE;
    cmd.updateType = SQL_CMD_UPDATE_UPLOAD_COL;

    memcpy(cmd.picName, picName, PIC_FILENAME_MAX_LEN);

    Packet *packTmp = PacketMalloc(sizeof(SqlAsyncCmd));
    copy_packet(packTmp, sizeof(SqlAsyncCmd), (uint8_t *)&cmd);
    sqlEnqueue(packTmp);
    dispatchSqlCmdExec();
    setRecvResponseTrue();
}

// 图片上传响应处理
void handlePicUploadRecvCmd(respon_pic_block_recv_t *picResult)
{
    uint8_t fileNo = picResult->pic_block_send_back_file_no;
    uint8_t camId = picResult->pic_block_send_back_cam_id;
    uint8_t picType = picResult->pic_block_send_back_pic_type;

    uint8_t timeBcd[BCD_TIME_LENGTH] = {0};
    memcpy(timeBcd, picResult->pic_block_send_back_time_bcd, BCD_TIME_LENGTH);

    uint8_t picName[PIC_FILENAME_MAX_LEN] = {0};
    genPicFileName(picName, fileNo, timeBcd, camId, picType);

    updateUploadColToSqlite(picName);
    LOG_INFO("图片(%s: %s.jpg)id( 文件序号:%d )接收完成", picType == BIG_PIC_TYPE ? "大图" : picType == SMALL_PIC_TYPE ? "小图"
                                                                                                                       : "标定", //
             picName, fileNo);

    uint8_t picPath[PIC_FILENAME_MAX_LEN] = {0};
    sprintf(picPath, "%s/%s.jpg", IMG_SAVE_DIR, picName);
    int8_t ret = unlink(picPath);
    if (ret == 0)
    {
        SqlAsyncCmd cmd = {0};

        cmd.cmdType = SQL_CMD_TYPE_UPDATE;
        cmd.updateType = SQL_CMD_UPDATE_DELETE_COL;
        memcpy(cmd.picName, picName, PIC_FILENAME_MAX_LEN);

        Packet *packTmp = PacketMalloc(sizeof(SqlAsyncCmd));
        copy_packet(packTmp, sizeof(SqlAsyncCmd), (uint8_t *)&cmd);
        sqlEnqueue(packTmp);
        dispatchSqlCmdExec();
    }
    else
    {
        LOG_ERROR("文件删除失败%s：%s", picPath, strerror(errno));
    }
}

// 上传标定数据
void handleCalibrationRecvCmd(respon_calibration_t *calibration_result)
{
    if (calibration_result->calibration_control_cmd == 0x01)
    {
        LOG_INFO("上传标定数据");
        Packet *gpsBuf = PacketMalloc(sizeof(gps_t));
        gps_t tmp = getLastGps();
        copy_packet(gpsBuf, sizeof(gps_t), (uint8_t *)&tmp);
        // hzlog_info(userLog, gpsBuf->pkt_data, gpsBuf->pkt_len);
        othersEnqueue(gpsBuf);
        dispatchSendPendingQueue();
    }
}

// 上传标定数据v2
void handleCalibrationRecvCmdV2(respon_calibration_v2_t *calibration_result)
{
    const uint8_t cmd = calibration_result->calibration_control_cmd_v2;
    if (cmd == 0x01)
    {
        LOG_INFO("开始标定v2");
        audioStartCalibrationV2();
        dispatchStartCalibrationV2();
    }
    else if (cmd == 0x02)
    {
        LOG_INFO("停止标定v2");
        audioStopCalibrationV2();
        dispatchStopCalibrationV2();
    }
}

void handleFileBlockFrameCmd(file_block_frame_t *pack, uint16_t recvLen)
{
    uint16_t fileCode = 0;
    uint8_t parseResult = parse_block((uint8_t *)pack, recvLen, &fileCode);
    uint16_t block_no = ntohs(pack->block_no);
    uint16_t block_num = ntohs(pack->block_num);

    switch (parseResult)
    {
    case FIRM_WARE_FAIL:
    {
        LOG_ERROR("固件包解析失败");
        uint8_t cmd[256] = {0};
        uint16_t file_name = ntohs(pack->file_id);
        uint16_t file_crc = ntohs(pack->calculate_file_crc);
        sprintf(cmd, PATH_NAME_FORMAT, FIRM_WARE_DIR, file_name, file_crc);
        unlink(cmd);
        break;
    }
    case FIRM_WARE_RECVING:
    {
        if (block_no != block_num - 1)
        {
            break;
        }
        send_firm_ware_response_last_one(true, fileCode);
        // LOG_INFO("全部块接收完成，接收块数 %d", firm_ware_block_receive_num);
    }
    case FIRM_WARE_DONE:
    {
        uint8_t path_name[256] = {0};
        uint16_t file_name = ntohs(pack->file_id);
        uint16_t file_crc = ntohs(pack->calculate_file_crc);
        uint16_t crcLocal = 0;

        LOG_DEBUG("程序接包成功：%d_%d", file_name, file_crc);
        sprintf(path_name, PATH_NAME_FORMAT, FIRM_WARE_DIR, file_name, file_crc);
        // 整文件crc校验
        if (calculate_file_crc(path_name, &crcLocal) == FILE_CRC_ERROR)
        {
            LOG_ERROR("收到的固件文件crc计算失败");
            goto FIRM_WARE_DONE_ERROR;
        }
        if (crcLocal != file_crc)
        {
            LOG_ERROR("固件crc校验失败，本地crc：%d；远程crc：%d", crcLocal, file_crc);
            goto FIRM_WARE_DONE_ERROR;
        }

        //  解压缩
        uint8_t cmd[256] = {0};
        sprintf(cmd, "cd /tmp/updateFirmware && gzip -dc %d_%d | tar -xvf -", file_name, file_crc);
        system(cmd);
        system("cd /tmp/updateFirmware && gzip -dc Tim.tar.gz | tar -xvf -");
        system("cd /tmp/updateFirmware && sh deploy.sh");
        int32_t systemRet = system("cd /tmp/updateFirmware && chmod a+x Tim && ./Tim");

        LOG_INFO("./Tim运行结果：%d", WEXITSTATUS(systemRet));
        if (WEXITSTATUS(systemRet) == TIM_REPEAT_RUN)
        {
            LOG_INFO("新固件可运行，执行deploy.sh来完成基本的部署工作，并且10秒后重启");
            uv_sleep(10 * 1000);
            system("reboot");
        }
        else
        {
            LOG_FATAL("新固件包Tim不可执行");
            goto FIRM_WARE_DONE_ERROR;
        };
        break;
    FIRM_WARE_DONE_ERROR:
        unlink(path_name);
    }
    default:
        break;
    }
}

// 分析某一块固件块并且写空洞文件
static uint8_t parse_block(uint8_t *buf, uint16_t packet_size, uint16_t *file_code)
{
    uv_loop_t *loop = getLoop();
    file_block_frame_t *pblk = (file_block_frame_t *)buf;
    // 固件包二进制打印
    // hzlog_info(userLog, pblk, packet_size);
    uint16_t block_num = ntohs(pblk->block_num);
    uint16_t block_no = ntohs(pblk->block_no);
    uint16_t file_type = ntohs(pblk->file_type);
    uint16_t last_bytes = ntohs(pblk->last_bytes);
    uint16_t file_id = ntohs(pblk->file_id);
    uint16_t file_crc = ntohs(pblk->calculate_file_crc);
    uint16_t body_len = ntohs(pblk->len);

    firm_ware_block_all_num = block_num;
    *file_code = file_id;

    uint8_t firm_ware_path[512] = {0};
    sprintf(firm_ware_path, PATH_NAME_FORMAT, FIRM_WARE_DIR, file_id, file_crc);

    int32_t fd = open(firm_ware_path, O_RDWR | O_CREAT);
    if (-1 == fd)
    {
        LOG_ERROR("创建固件缓存文件失败");
        return FIRM_WARE_FAIL;
    }
    if (block_no == 0)
    {
        // LOG_DEBUG("文件id：%d，分块序号：%d, 总块数=%d, 文件类型=0x%x, 最后一包字节数=%d, 总文件大小=%d",
        //           file_id, block_no, block_num, file_type, last_bytes, (block_num - 1) * FILE_BLOCK_SIZE + last_bytes);

        uint16_t first_block_write_size = 0;
        bool isOnePack = block_num == 1 ? true : false;
        if (isOnePack == true)
        {
            first_block_write_size = last_bytes;
        }
        else
        {
            first_block_write_size = FILE_BLOCK_SIZE;
        }

        write(fd, pblk->body, first_block_write_size);
        fsync(fd);
        close(fd);
        if (isOnePack == true)
        {
            return FIRM_WARE_DONE;
        }
        return FIRM_WARE_RECVING;
    }

    if (block_no < block_num - 1)
    {
        // 中间块
        if (-1 == lseek(fd, block_no * FILE_BLOCK_SIZE, SEEK_SET))
        {
            // LOG_ERROR("中间块写失败，原因：%s", strerror(errno));
            goto FIRM_WARE_FAIL_DO_THING;
        }
        write(fd, pblk->body, FILE_BLOCK_SIZE);
        fsync(fd);
        close(fd);
        return FIRM_WARE_RECVING;
    }
    else
    {
        // last block
        uint16_t crc;

        if (-1 == lseek(fd, block_no * FILE_BLOCK_SIZE, SEEK_SET))
        {
            // LOG_ERROR("中间块写失败，原因：%s", strerror(errno));
            goto FIRM_WARE_FAIL_DO_THING;
        }
        write(fd, pblk->body, last_bytes);
        // LOG_INFO("已经接收到最后块，文件指针位置: %ld bytes", lseek(fd, 0, SEEK_CUR));
        LOG_INFO("已经接收到固件最后块");
        fsync(fd);
        close(fd);
    }

    return FIRM_WARE_RECVING;

FIRM_WARE_FAIL_DO_THING:
    unlink(firm_ware_path);
    return FIRM_WARE_FAIL;
}

// 固件包回复idle事件注册
static void start_idle_response_task(uint16_t block_no)
{
    while (uv_is_active((uv_handle_t *)&idler) != 0)
    {
        // LOG_NOTICE("空闲事件正在使用中，等待释放");
        uv_sleep(50);
    }

    uv_idle_init(getLoop(), &idler);

    uint16_t *block_no_t = (uint16_t *)malloc(sizeof(uint16_t));
    *block_no_t = block_no;
    idler.data = block_no_t;

    uv_idle_start(&idler, send_firm_ware_response);
}

// 固件包回复帧初始化
static void firmwareFrameInit(file_block_send_t *block, bool isSuccess, uint16_t fileCode)
{
    headInit((head_t *)block, FIRMWARE_CMD);
    block->file_block_type = htons(0x9999);
    block->file_block_file_code = htons(fileCode);
    block->file_block_response_code = isSuccess == true ? htonl(0x01) : htonl(0x10);
    block->len = CAL_FRAME_DATA_LEN_TO_NET(file_block_send_t);
    block->crc = htons(crc((uint8_t *)block + CRC_BASE_ADDR(file_block_send_t), sizeof(file_block_send_t) - MEM_SIZE(file_block_send_t, crc) - MEM_SIZE(file_block_send_t, head)));
}

// !目前是不可用的
// 固件包回应
static void send_firm_ware_response(uv_idle_t *handle)
{
    Packet *blockPack = PacketMalloc(sizeof(file_block_send_t));

    file_block_send_t block = {0};
    uint16_t *block_no = (uint16_t *)handle->data;

    firmwareFrameInit(&block, false, 0);
    free(block_no);

    copy_packet(blockPack, sizeof(file_block_send_t), (uint8_t *)&block);
    othersEnqueue(blockPack);
    dispatchSendPendingQueue();
    uv_idle_stop(handle);
}

// 固件包回应
static void send_firm_ware_response_last_one(bool isSuccess, uint16_t fileCode)
{
    Packet *blockPack = PacketMalloc(sizeof(file_block_send_t));

    file_block_send_t block = {0};

    firmwareFrameInit(&block, isSuccess, fileCode);

    copy_packet(blockPack, sizeof(file_block_send_t), (uint8_t *)&block);
    othersEnqueue(blockPack);
    dispatchSendPendingQueue();
}

static void setReserveFrame(uint8_t *buf, ssize_t len)
{
    reserveFrame.isReserve = true;
    reserveFrame.reserveLen = len;
    memcpy(reserveFrame.reserveBuf, buf, len);
}